#include <signal.h>
#include <android/log.h>
#include <string>
#include "spidev.h"
#include "spi.h"

#define LOG_TAG  "C_TAG"
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

using namespace std;
///boost::function<void (int x)> irqSignalHandler;
///
/// \brief 该函数用来接收从内核传来的中断信息
/// \param sig
///
///void IrqSignalHandler(int sig)
///{
//    irqSignalHandler(sig);
///}

Spi::Spi(string device, u_int32_t speed, u_int8_t bits) :
        devicePath(device),
        speed(speed),
        bits(bits),
        isConnected(false),
        deviceFd(0),
        mode(0x00),
        delay(0)
{
    pthread_mutex_init(&spiMutex, NULL);
    // 被注释
    /// signal(SIGIO, IrqSignalHandler);
}

int Spi::Init()
{
    int ret;

    deviceFd = open(devicePath.c_str(), O_RDWR);
    if (deviceFd < 0)
    {
        puts("can't open device");
        return -1;
    }

    /*
     * max speed hz
     */
    ret = ioctl(deviceFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret == -1)
    {
        puts("can't set max speed hz");
        return -6;
    }

    ret = ioctl(deviceFd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
    if (ret == -1)
    {
        puts("can't get max speed hz");
        return -7;
    }

    /*
     * spi mode
     */
    ret = ioctl(deviceFd, SPI_IOC_WR_MODE, &mode);
    if (ret == -1)
    {
        puts("can't set spi mode");
        return -2;
    }

    ret = ioctl(deviceFd, SPI_IOC_RD_MODE, &mode);
    if (ret == -1)
    {
        puts("can't get spi mode");
        return -3;
    }

    /*
     * bits per word
     */
    ret = ioctl(deviceFd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    if (ret == -1)
    {
        puts("can't set bits per word");
        return -4;
    }

    ret = ioctl(deviceFd, SPI_IOC_RD_BITS_PER_WORD, &bits);
    if (ret == -1)
    {
        puts("can't get bits per word");
        return -5;
    }

    fcntl(deviceFd, F_SETFD, FD_CLOEXEC); ///< 子进程不继承该描述符
    fcntl(csPinFd, F_SETFD, FD_CLOEXEC);  ///< 子进程不继承该描述符

    printf("spi mode: %d\n", mode);
    printf("bits per word: %d\n", bits);
    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

    isConnected = true;

    close(csPinFd);
    csPinFd = open("/dev/SPI_INTERRUPT_AND_CS_CONTROL", O_RDWR);
    fcntl(csPinFd, F_SETOWN, getpid());
    fcntl(csPinFd, F_SETFL, fcntl(csPinFd, F_GETFL) | FASYNC);
    CsPinControl(IOCTL_CRTL_HIGHT);

    return 1;
}

void Spi::CsPinControl(long flag)
{
    ioctl(csPinFd, flag, NULL);
}

u_int8_t Spi::GetIntPinStatus()
{
    return read(csPinFd, NULL, 0);
}

int Spi::WriteByte(u_int8_t address, u_int8_t data)
{
    u_int8_t txBuf[1 + 2];
    u_int8_t rxBuf[1 + 2];

    txBuf[0] = 0x02;
    txBuf[1] = address;
    txBuf[2] = data;

    if(transfer(txBuf, rxBuf, 1 + 2) == 1)
    {
        printf("Can't send data\n");
//        LOGD("Can't send data\n");
        return -1;
    }else
    {
//       LOGD("Can send data\n");
        return 1;
    }
}

int Spi::WriteOneByte(u_int8_t data)
{
    u_int8_t txBuf[1];
    u_int8_t rxBuf[1];

    txBuf[0] = data;

    if(transfer(txBuf, rxBuf, 1) == 1)
    {
        return -1;
    }else
    {
        return 1;
    }
}

u_int8_t Spi::ReadByte(u_int8_t cmd)
{
    u_int8_t txBuf[3];
    u_int8_t rxBuf[3];

    txBuf[0] = 0x03;
    txBuf[1] = cmd;
    txBuf[2] = 0x00;
    if(transfer(txBuf, rxBuf, 3) == 1)
    {
        printf("Can't send data\n");
        return -1;
    }else
    {
        return rxBuf[2];
    }
}

int Spi::Write(u_int8_t address, u_int8_t* dataBuf, int len)
{
    u_int8_t txBuf[len + 2];
    u_int8_t rxBuf[len + 2];

    txBuf[0] = 0x02;
    txBuf[1] = address;

    memcpy(txBuf + 2, dataBuf, len);

    if(transfer(txBuf, rxBuf, len + 2) == 1)
    {
        printf("Can't send data\n");
        return -1;
    } else
    {
        //LOGD("data: %2x %2x %2x %2x  \r\n", txBuf[2], txBuf[3],txBuf[4],txBuf[5]);
//       LOGD("rx data: %2x %2x %2x %2x  \r\n", rxBuf[2], rxBuf[3],rxBuf[4],rxBuf[5]);
        return 1;
    }
}

int Spi::Read(u_int8_t address, u_int8_t* readBuf, int len)
{
    u_int8_t txBuf[len + 2];
    u_int8_t rxBuf[len + 2];

    bzero(txBuf, len + 2);
    txBuf[0] = 0x03;
    txBuf[1] = address;

    if(transfer(txBuf, rxBuf, len + 2) == 1)
    {
        printf("Can't send data\n");
        return -1;
    }else
    {
        memcpy(readBuf, rxBuf + 2, len);
        return 1;
    }
}

int Spi::transfer(u_int8_t *sendBuf, u_int8_t *readBuf, int len)
{
    struct spi_ioc_transfer tr;

    tr.tx_buf = (unsigned long)sendBuf;
    tr.rx_buf = (unsigned long)readBuf;
    tr.len = len;
    tr.delay_usecs = delay;
    tr.speed_hz = speed;
    tr.bits_per_word = bits;

    pthread_mutex_lock(&spiMutex);
    CsPinControl(IOCTL_CRTL_LOW);
    int result = ioctl(deviceFd, SPI_IOC_MESSAGE(1), &tr);
    CsPinControl(IOCTL_CRTL_HIGHT);
    pthread_mutex_unlock(&spiMutex);
    return result;
}

u_int8_t Spi::ReadStatus()
{
    u_int8_t txBuf[2];
    u_int8_t rxBuf[2];

    txBuf[0] = 0xa0;

    if(transfer(txBuf, rxBuf, 2) == 1)
    {
        printf("Can't send data\n");
        return -1;
    }else
    {
        return rxBuf[1];
    }
}

int Spi::ModifyRegister(const u_int8_t RegAddr, const u_int8_t mask, const u_int8_t data)
{
    u_int8_t txBuf[4];
    u_int8_t rxBuf[4];

    txBuf[0] = 0x05;
    txBuf[1] = RegAddr;
    txBuf[2] = mask;
    txBuf[3] = data;

    if(transfer(txBuf, rxBuf, 4) == 1)
    {
        printf("Can't send data\n");
        return -1;
    }else
    {
        return 1;
    }
}

int Spi::FastWriteTxBuf(const u_int8_t regNum, const u_int8_t* buf, const u_int8_t len)
{
    u_int8_t txBuf[len + 1];
    u_int8_t rxBuf[len + 1];

    txBuf[0] = 0x40 | regNum;

    memcpy(txBuf + 1, buf, len);

    if(transfer(txBuf, rxBuf, len + 1) == 1)
    {
        printf("Can't send data\n");
//        LOGD("Can't send data\n");
        return -1;
    }else
    {
//        LOGD("Can send data\n");
        return 1;
    }
}


int Spi::FastReadRxBuf(const u_int8_t regNum, u_int8_t *buf)//the size of buf must longer than 13
{
    u_int8_t txBuf[13 + 1];
    u_int8_t rxBuf[13 + 1];

    txBuf[0] = 0x90 | ((regNum << 1) & 0x06);

    if(transfer(txBuf, rxBuf, 13 + 1) == 1)
    {
        printf("Can't send data\n");
        return -1;
    }else
    {
        memcpy(buf, rxBuf + 1, 13);
        return 1;
    }
}

